/* 
  Copyright (c) SilverLining 2015
  Date:    2016-1-7
  File:    Archiver.h  
  Description: 
    The managed archiver class.

*/

#pragma once

namespace SL
{
	namespace M
	{
		/// <summary>
		/// Represent an object archiver. The archiver persists a root object, maintaining any internal object references.
		/// </summary>
		/// <example>
		/// <para>The following example shows how to read an archive from a binary file.</para>
		/// <code>			
		/// TextArchiver a = new TextArchiver();
		/// GameObject o = CreateObjectGraph();
		/// GameObject o2 = CreateObjectGraph();

		/// InitGraph(o);
		/// string s = a.Archive(o);
		/// Console.Out.WriteLine(s);
		/// TestArchive(a, o);
		/// a.Unarchive(o2, s);
		/// TestArchive(a, o2);
		/// </code>
		/// </example>
		public ref class Archiver
		{
		public:
			~Archiver();
			!Archiver();

			/// <summary>
			/// Write the start of an array.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			void WriteArrayStart(String^ name);
			/// <summary>
			/// Write the start of an array from inside an array.
			/// </summary>
			void WriteArrayStart();
			/// <summary>
			/// Write an array value.
			/// </summary>
			/// <param name="obj">The object to write.</param>
			void WriteArrayValue(GameObject^ obj);
			/// <summary>
			/// Write an array value.
			/// </summary>
			/// <param name="num">The number to write.</param>
			void WriteArrayValue(double num);
			/// <summary>
			/// Write an array value.
			/// </summary>
			/// <param name="num">The number to write.</param>
			void WriteArrayValue(signed char num);
			/// <summary>
			/// Write an array value.
			/// </summary>
			/// <param name="num">The number to write.</param>
			void WriteArrayValue(Int16 num);
			/// <summary>
			/// Write an array value.
			/// </summary>
			/// <param name="num">The number to write.</param>
			void WriteArrayValue(Int32 num);
			/// <summary>
			/// Write an array value.
			/// </summary>
			/// <param name="num">The number to write.</param>
			void WriteArrayValue(Int64 num);
			/// <summary>
			/// Write an array value.
			/// </summary>
			/// <param name="string">The string to write.</param>
			void WriteArrayValue(String^ string);
			/// <summary>
			/// Write an array value.
			/// </summary>
			/// <param name="bit">The boolean to write.</param>
			void WriteArrayValue(bool bit);
			/// <summary>
			/// Write an array value.
			/// </summary>
			/// <param name="data">The binary data to write.</param>
			void WriteArrayBytes(array<byte>^ data);
			/// <summary>
			/// Write the end of an array.
			/// </summary>
			void WriteArrayEnd();

			/// <summary>
			/// Write an object.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			/// <param name="obj">The object to write.</param>
			void WriteValue(String^ name, GameObject^ obj);
			/// <summary>
			/// Write a number.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			/// <param name="num">The value to write.</param>
			void WriteValue(String^ name, double num);
			/// <summary>
			/// Write a number.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			/// <param name="num">The value to write.</param>
			void WriteValue(String^ name, signed char num);
			/// <summary>
			/// Write a number.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			/// <param name="num">The value to write.</param>
			void WriteValue(String^ name, Int16 num);
			/// <summary>
			/// Write a number.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			/// <param name="num">The value to write.</param>
			void WriteValue(String^ name, Int32 num);
			/// <summary>
			/// Write a number.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			/// <param name="num">The value to write.</param>
			void WriteValue(String^ name, Int64 num);
			/// <summary>
			/// Write a string.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			/// <param name="string">The null-terminated string to write.</param>
			void WriteValue(String^ name, String^ string);
			/// <summary>
			/// Write a boolean.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			/// <param name="val">The boolean to write.</param>
			void WriteValue(String^ name, bool val);
			/// <summary>
			/// Write a byte array.
			/// </summary>
			/// <param name="name">The name of the value to write.</param>
			/// <param name="data">The byte array to write.</param>
			void WriteBytes(String^ name, array<byte>^ data);

			/// <summary>
			/// Read the start of an array.
			/// </summary>
			/// <param name="name">The name of the array to read.</param>
			/// <param name="sz">A required parameter holding the size of the array.</param>
			/// <returns>True if the array could be read.</returns>
			bool ReadArrayStart(String^ name, int% sz);
			/// <summary>
			/// Read the start of an array.
			/// </summary>
			/// <param name="index">The index of the array to read.</param>
			/// <param name="sz">A required parameter holding the size of the array.</param>
			/// <returns>True if the array could be read.</returns>
			bool ReadArrayStart(int index, int% sz);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="index">The index of the value to read.</param>
			/// <param name="object">The value to read.</param>
			generic <class T> where T : GameObject
			void ReadArrayObject(int index, T% object);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="index">The index of the value to read.</param>
			/// <returns>An number if one could be read.</returns>
			/// <remarks>If a value could not be read, the default value will be returned instead.</remarks>
			double ReadArrayDouble(int index);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="index">The index of the value to read.</param>
			/// <returns>An number if one could be read.</returns>
			/// <remarks>If a value could not be read, the default value will be returned instead.</remarks>
			signed char ReadArraySByte(int index);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="index">The index of the value to read.</param>
			/// <returns>An number if one could be read.</returns>
			/// <remarks>If a value could not be read, the default value will be returned instead.</remarks>
			int16_t ReadArrayShort(int index);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="index">The index of the value to read.</param>
			/// <returns>An number if one could be read.</returns>
			/// <remarks>If a value could not be read, the default value will be returned instead.</remarks>
			int32_t ReadArrayInt(int index);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="index">The index of the value to read.</param>
			/// <returns>An number if one could be read.</returns>
			/// <remarks>If a value could not be read, the default value will be returned instead.</remarks>
			int64_t ReadArrayLong(int index);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="index">The index of the value to read.</param>
			/// <returns>An string if one could be read.</returns>
			/// <remarks>If a value could not be read, the default value will be returned instead.</remarks>
			String^ ReadArrayString(int index);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="index">The index of the value to read.</param>
			/// <returns>An boolean if one could be read.</returns>
			/// <remarks>If a value could not be read, the default value will be returned instead.</remarks>
			bool ReadArrayBool(int index);
			/// <summary>
			/// Read a byte array value.
			/// </summary>
			/// <param name="index">The index of the value to read.</param>
			/// <returns>The byte array which was read.</returns>
			/// <remarks>If a value could not be read, the default value will be returned instead.</remarks>
			array<byte>^ ReadArrayBytes(int index);
			/// <summary>
			/// Read the end of an array.
			/// </summary>
			void ReadArrayEnd();

			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="name">The name of the value to read.</param>
			/// <param name="object">The value to read.</param>
			generic <class T> where T : GameObject
			void ReadObject(String^ name, T% object);

			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="name">The name of the value to read.</param>
			/// <returns>A parameter which will hold the read value, or be default initialized if no value was read.</returns>
			double ReadDouble(String^ name);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="name">The name of the value to read.</param>
			/// <returns>A parameter which will hold the read value, or be default initialized if no value was read.</returns>
			signed char ReadSByte(String^ name);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="name">The name of the value to read.</param>
			/// <returns>A parameter which will hold the read value, or be default initialized if no value was read.</returns>
			int16_t ReadShort(String^ name);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="name">The name of the value to read.</param>
			/// <returns>A parameter which will hold the read value, or be default initialized if no value was read.</returns>
			int32_t ReadInt(String^ name);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="name">The name of the value to read.</param>
			/// <returns>A parameter which will hold the read value, or be default initialized if no value was read.</returns>
			int64_t ReadLong(String^ name);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="name">The name of the value to read.</param>
			/// <returns>A parameter which will hold the read value, or be default initialized if no value was read.</returns>
			String^ ReadString(String^ name);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="name">The name of the value to read.</param>
			/// <returns>A parameter which will hold the read value, or be default initialized if no value was read.</returns>
			bool ReadBool(String^ name);
			/// <summary>
			/// Read a value.
			/// </summary>
			/// <param name="name">The name of the value to read.</param>
			/// <returns>A parameter which will hold the read value, or be default initialized if no value was read.</returns>
			array<byte>^ ReadBytes(String^ name);

			/// <summary>
			/// Represent the native archiver for this object.
			/// </summary>
			property m::archiver* NativeArchiver
			{
				/// <summary>
				/// Return the native archiver for this object.
				/// </summary>
				/// <returns>A pointer to the native archiver.</returns>
				m::archiver* get();
			}

		internal:
			Archiver();
			Archiver(m::archiver* archiver);

			void Archive(GameObject^ root, m::serializer* serializer);
			void Unarchive(GameObject^ root, m::serializer* serializer);

			m::archiver* _Archiver;
		};
	}
}
